package net.jacqeush.mini.server;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import lombok.extern.slf4j.Slf4j;
import net.jacqeush.mini.rpc.codec.Decoder;
import net.jacqeush.mini.rpc.codec.Encoder;
import net.jacqeush.mini.rpc.codec.model.Request;
import net.jacqeush.mini.rpc.codec.model.Response;
import net.jacqeush.mini.server.config.ProviderConfig;
import net.jacqeush.mini.server.hander.SeverHandler;


import java.util.HashMap;

/**
 * @author Jacquesh
 * @version 1.0
 * @date 2020/10/17 2:20
 */
@Slf4j
public class RpcServer {
    private String socketAddress;
    private EventLoopGroup bossGroup = new NioEventLoopGroup();
    private EventLoopGroup workerGroup = new NioEventLoopGroup();
    private  volatile HashMap<String,Object> handlerMaps=new HashMap<String,Object>();
    public RpcServer(String socketAddress) throws InterruptedException {
         this.socketAddress = socketAddress;
         this.start();
    }
    private void start() throws InterruptedException {
        ServerBootstrap b=new ServerBootstrap();
        b.group(bossGroup, workerGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.SO_BACKLOG, 1024).childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel socketChannel) throws Exception {
                ChannelPipeline cp = socketChannel.pipeline();
                cp.addLast(new LengthFieldBasedFrameDecoder(65536, 0, 4, 0, 0));
                cp.addLast(new Decoder(Request.class));
                cp.addLast(new Encoder(Response.class));
                cp.addLast(new SeverHandler(handlerMaps));
            }
        });
        String[] array=this.socketAddress.split(":");
        if (array.length==2){
          String host=array[0];
          int port=Integer.parseInt(array[1]);
          ChannelFuture channelFuture=b.bind(host,port).sync();
          channelFuture.addListener(new ChannelFutureListener() {
              @Override
              public void operationComplete(ChannelFuture future) throws Exception {
               if(future.isSuccess()){
                   log.info("channel connect success:"+this.getClass());
               }else {
                   log.error("channel server start error:"+this.getClass()+"   cause:"+future.cause());
                   throw  new Exception("channel server start error:"+this.getClass()+"   cause:"+future.cause());
               }
              }
          });
        }

    }
    public void registerProcessor(ProviderConfig providerConfig) {
        /* key ：(Service接口权限命名)
         * value ：(userService接口下的具体实现类 userServiceImpl实例对象)*/
        handlerMaps.put(providerConfig.getInterfaceClass(), providerConfig.getRef());
    }
    public  void close(){
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }
}
